/**
 * Copyright (C) 2010 altuure <altuure [AT] gmail [DOT] com> http://www.altuure.com/projects/yagdao
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.altuure.yagdao.hibernate;

import com.altuure.yagdao.YLimit;
import com.altuure.yagdao.base.DAOTestHelper;
import com.altuure.yagdao.dao.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.junit.Rule;
import org.junit.rules.TestName;

import java.util.List;
import java.util.Map;

public class HibernateDAOTestHelper extends DAOTestHelper {

    public static final Log log = LogFactory.getLog(HibernateDAOTestHelper.class);
    @Rule
    public TestName name = new TestName();

    private SessionFactory sessionFactory;
    private DefaultHibernateSessionAccessor sessionAccessor;
    private Transaction tx;
    private static HibernateDAOTestHelper instance = null;

    private HibernateDAOTestHelper() {
        super();

    }

    public static synchronized HibernateDAOTestHelper getInstance() {

        if (instance == null) {
            instance = new HibernateDAOTestHelper();
            try {
                instance.init();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return instance;
    }

    public static synchronized void setInstance(HibernateDAOTestHelper instance) {
        HibernateDAOTestHelper.instance = instance;
    }

    @Override
    protected void initDAO() throws Exception {

        orderDAO = (OrderDAO) GenericHibernateDAOFactory.createInstance(OrderDAO.class, sessionAccessor);
        orderItemDAO = (OrderItemDAO) GenericHibernateDAOFactory.createInstance(OrderItemDAO.class, sessionAccessor);
        productDAO = (ProductDAO) GenericHibernateDAOFactory.createInstance(ProductDAO.class, sessionAccessor);
        simpleBeanDAO = (SimpleBeanDAO) GenericHibernateDAOFactory.createInstance(SimpleBeanDAO.class, sessionAccessor);
        simpleBeanNewDAO = (SimpleBeanNewDAO) GenericHibernateDAOFactory.createInstance(SimpleBeanNewDAO.class, sessionAccessor);
        simpleBeanAppendDAO= (SimpleBeanAppendDAO) GenericHibernateDAOFactory.createInstance(SimpleBeanAppendDAO.class, sessionAccessor);
    }

    @Override
    protected void initDB() {

        if (sessionFactory != null)
            return;
        sessionFactory = new AnnotationConfiguration().configure("META-INF/hibernate.cfg.xml").buildSessionFactory();
        sessionAccessor = new DefaultHibernateSessionAccessor(sessionFactory);

    }

    @Override
    public void save(Object object) {
        sessionAccessor.getCurrentSession().save(object);

    }

    @Override
    protected void beginTx() {
        Session session = sessionAccessor.getCurrentSession();

        tx = session.beginTransaction();
        session.clear();

    }

    @Override
    protected void commitTx() {
        tx.commit();
        sessionAccessor.getCurrentSession().close();

    }

    @Override
    protected void rollbackTx() {
        tx.rollback();
        sessionAccessor.getCurrentSession().close();

    }

    @Override
    public Object executePageQuery(String queryString, YLimit page, Object... args) {
        Query query = sessionAccessor.getCurrentSession().createQuery(queryString);
        if (args != null) {
            for (int i = 0; i < args.length; i++) {
                Object object = args[i];
                query.setParameter(i, object);
            }
        }
        if (page != null && page.getFirstResult() > 0)
            query.setFirstResult(page.getFirstResult());
        if (page != null && page.getPageSize() > 0)
            query.setMaxResults(page.getPageSize());

        List list = query.list();
        if (list.isEmpty())
            log.warn(name.getMethodName() + " queryReturns empty:" + queryString);
        return list;

    }

    @Override
    public Object executePageQuery(String queryString, YLimit page, Map<String, Object> args) {
        Query query = sessionAccessor.getCurrentSession().createQuery(queryString);
        for (String key : args.keySet()) {

            query.setParameter(key, args.get(key));
        }
        if (page != null && page.getFirstResult() > 0)
            query.setFirstResult(page.getFirstResult());
        if (page != null && page.getPageSize() > 0)
            query.setMaxResults(page.getPageSize());

        List list = query.list();
        if (list.isEmpty())
            log.warn(name.getMethodName() + " queryReturns empty:" + queryString);
        return list;

    }

    public Object executeSingleQuery(String queryString, Object... args) {
        Query query = sessionAccessor.getCurrentSession().createQuery(queryString);
        if (args != null) {
            for (int i = 0; i < args.length; i++) {
                Object object = args[i];
                query.setParameter(i + 1, object);
            }
        }

        return query.uniqueResult();
    }

    public Object executeSingleQuery(String queryString, Map<String, Object> args) {
        Query query = sessionAccessor.getCurrentSession().createQuery(queryString);
        for (String key : args.keySet()) {

            query.setParameter(key, args.get(key));
        }

        return query.uniqueResult();
    }

    @Override
    public Object executeQuery(String queryString, Object... args) {
        return executePageQuery(queryString, null, args);
    }

    public static void main(String[] args) throws Exception {
        new HibernateDAOTestHelper();
    }

    @Override
    public Object get(Class clz, Long id) {
        return sessionAccessor.getCurrentSession().get(clz, id);
    }

    @Override
    public Object executeNamedQuery(String queryString, YLimit page, Map<String, Object> args) {
        Query query = sessionAccessor.getCurrentSession().getNamedQuery(queryString);
        for (String key : args.keySet()) {

            query.setParameter(key, args.get(key));
        }
        if (page != null && page.getFirstResult() > 0)
            query.setFirstResult(page.getFirstResult());
        if (page != null && page.getPageSize() > 0)
            query.setMaxResults(page.getPageSize());

        return query.list();
    }

    @Override
    public Object executeNamedQuery(String queryString, YLimit page, Object... args) {
        Query query = sessionAccessor.getCurrentSession().getNamedQuery(queryString);
        for (int i = 0; i < args.length; i++) {
            Object object = args[i];
            query.setParameter(i, object);
        }
        if (page != null && page.getFirstResult() > 0)
            query.setFirstResult(page.getFirstResult());
        if (page != null && page.getPageSize() > 0)
            query.setMaxResults(page.getPageSize());

        return query.list();
    }

}
